package com.lambda.widget;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.customview.widget.ViewDragHelper;

import com.lambda.sidget.R;

public class LSwipeBackLayout extends ViewGroup {
    private final String TAG = "LSwipeBackLayout";
    private ViewDragHelper mDragHelper;
    private View mContentView;
    private boolean mInLayout;
    private int mScrollPosLeft;
    private boolean mSettling;
    private boolean mConversionTranslucentCompleted;
    private boolean mNeedChangeWindowBackground = true;
    private Drawable mShadowDrawable;
    private Rect mRect = new Rect();
    private float mSwipePercent;
    private float mShadowAlpha;
    public SwipeGestureDelegate mGestureDelegate;

    public interface SwipeGestureDelegate {
        void onCancel();

        void onDrag();

        void onSwipeBack();
    }

    private class Callback extends ViewDragHelper.Callback implements Utils.TranslucentConversionListener {
        @Override
        public boolean tryCaptureView(@NonNull View child, int pointerId) {
            return (mDragHelper.isEdgeTouched(ViewDragHelper.EDGE_LEFT) && (child == mContentView));
        }

        @Override
        public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {
            if (mSettling) {
                mSettling = false;
                mDragHelper.cancel();
            }
        }

        @Override
        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
            int result;
            if (mConversionTranslucentCompleted) {
                result = Math.max(mScrollPosLeft, left);
                mScrollPosLeft = 0;
            } else {
                mScrollPosLeft = Math.max(mScrollPosLeft, left);
                result = 0;
            }
            LogUtils.log(TAG, "clampViewPositionHorizontal left: %d, dx: %d", mScrollPosLeft, dx);
            return result;
        }

        @Override
        public void onViewDragStateChanged(int state) {
            if (ViewDragHelper.STATE_DRAGGING == state) {
                Context context = getContext();
                if (context instanceof Activity) {
                    if (mNeedChangeWindowBackground) {
                        ((Activity) context).getWindow().getDecorView().setBackgroundResource(R.color.a_q);
                    }

                    if (!mConversionTranslucentCompleted) {
                        Utils.convertToTranslucent((Activity) context, this);
                    }
                }
            }
        }

        @Override
        public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
            if (!mConversionTranslucentCompleted) return;

            mSwipePercent = Math.abs((float) left / (mContentView.getWidth() + mShadowDrawable.getIntrinsicWidth()));
            invalidate();

            if (mSwipePercent > 1.0f && mGestureDelegate != null) {
                mGestureDelegate.onSwipeBack();
            }
        }

        @Override
        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
            LogUtils.log(TAG, "onViewReleased xvel: " + xvel + ", yvel: " + yvel);
            mSettling = true;

            int finalLeft;
            if (xvel > 3800 || mSwipePercent > 0.45) {
                finalLeft = mContentView.getMeasuredWidth() + mShadowDrawable.getIntrinsicWidth() + 66;
            } else {
                finalLeft = 0;
            }

            if (mDragHelper.settleCapturedViewAt(finalLeft, 0)) {
                invalidate();
            }
        }

        @Override
        public void onTranslucentConversionComplete(boolean complete) {
            LogUtils.log(TAG, "onTranslucentConversionComplete completed: %b", complete);
            mConversionTranslucentCompleted = complete;
        }
    }

    @Override
    public void computeScroll() {
        mShadowAlpha = Math.max(0.0f, 1.0f - mSwipePercent);

        if (mDragHelper.continueSettling(false)) {
            invalidate();
        } else {
            mSettling = false;
        }
    }

    public LSwipeBackLayout(Context context) {
        super(context);
        init(context, null);
    }

    public LSwipeBackLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public LSwipeBackLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        mDragHelper = ViewDragHelper.create(this, new Callback());

        mShadowDrawable = ContextCompat.getDrawable(context, R.drawable.shadow);

        setFocusable(true);
        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        for (int i = 0; i < getChildCount(); i += 1) {
            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mInLayout = true;
        if (mContentView != null) {
            int measuredWidth = mContentView.getMeasuredWidth();
            mContentView.layout(mScrollPosLeft, t, mScrollPosLeft + measuredWidth, b);
        }
        mInLayout = false;
    }

    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        boolean result = super.drawChild(canvas, child, drawingTime);
        if (mContentView != null && mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE && mSwipePercent > 0f) {
            child.getHitRect(mRect);
            mShadowDrawable.setBounds(mRect.left - mShadowDrawable.getIntrinsicWidth(), mRect.top, mRect.left, mRect.bottom);
            mShadowDrawable.setAlpha((int) (mShadowAlpha * 255.0f));
            mShadowDrawable.draw(canvas);
        }
        return result;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        mDragHelper.processTouchEvent(ev);
        return true;
    }

    @Override
    public void requestLayout() {
        if (!mInLayout) {
            super.requestLayout();
        }
    }

    public void setContentView(View view) {
        mContentView = view;
    }

    public void setSwipeGestureDelegate(SwipeGestureDelegate delegate) {
        mGestureDelegate = delegate;
    }
}
